package com.fuda.trade

import com.fuda.trade.model.Heartbeat
import com.fuda.trade.model.TradeOrderData
import io.zenoh.Session
import io.zenoh.keyexpr.KeyExpr
import io.zenoh.publication.CongestionControl
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.junit.jupiter.api.Test
import java.time.LocalDateTime
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlin.random.Random

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */

class ZPubTest {

    @Test
    fun testPublish() = runBlocking<Unit>  {
        val latch = CountDownLatch(1)
        println("Press CTRL-C to quit...")

        // Print the current value of the DYLD_LIBRARY_PATH environment variable.
        println("Current DYLD_LIBRARY_PATH: ${System.getenv("DYLD_LIBRARY_PATH")}")

        // Refer to build.gradle.kts
        // tasks.withType<Test> {
        //     // Set the java.library.path system property to include the directory where the JNI library is located.
        //     environment("DYLD_LIBRARY_PATH", "/Users/CC/github/eclipse-zenoh/zenoh-java/zenoh-jni/target/release")
        //
        //     useJUnitPlatform()
        // }

        val repeatTimes = 3;  //    Short.MAX_VALUE.toInt()

        println("Opening session...")
        val mainScope = CoroutineScope(Dispatchers.IO)

        val rc =mainScope.launch {
            Session.open().use{ session ->
                KeyExpr.tryFrom( ZenohManager.ZENOH_RESPONSE_TOPIC ).use { keyExpr ->
                    println("Declaring publisher on '$keyExpr'...")
                    session.declarePublisher(keyExpr).congestionControl(CongestionControl.BLOCK).res().use{ publisher ->
                        TimeUnit.SECONDS.sleep(10) // Sleep for 10 seconds
                        var idx = 0
                        repeat(repeatTimes) {
                            val now = LocalDateTime.now()
                            val buyAutoTradeOrderData = TradeOrderData.Buy(
                                securityCode = "SH.STK.600519",
                                securityName = "SH.STK.600519",
                                pricingType = TradeOrderData.PricingType.Limit,
                                price = 160+ Random(160).nextDouble(),
                                volume = 100,
                                desc = "Publish$idx@ZPubTest.kt",
                                isAuto = true)
                            val payload = TradeOrderData.serialize(buyAutoTradeOrderData)

                            println(">> $now Putting Data ('$keyExpr': '$payload')...")
                            publisher.put(payload).res()
                            idx++
                            TimeUnit.SECONDS.sleep(15) // Sleep for 3 seconds
                        }
                    }
                }
            }
        }

        val hbc = mainScope.launch {
            Session.open().use{ session ->
                KeyExpr.tryFrom( ZenohManager.ZENOH_HEARTBEAT_TOPIC ).use { keyExpr ->
                    println("Declaring publisher on '$keyExpr'...")
                    session.declarePublisher(keyExpr).congestionControl(CongestionControl.BLOCK).res().use { publisher ->
                        TimeUnit.SECONDS.sleep(10) // Sleep for 10 seconds
                        var idx = 0
                        while(true) {
                            val now = LocalDateTime.now()
                            val serverHb = Heartbeat.Server(
                                id = "$idx",
                                timestampMs = System.currentTimeMillis(),
                                desc = "Publish$idx@ZPubTest.kt")
                            val payload = Heartbeat.serialize(serverHb)

                            println(">> $now Putting Data ('$keyExpr': '$payload')...")
                            publisher.put(payload).res()
                            idx++
                            TimeUnit.SECONDS.sleep(5) // Sleep for 3 seconds
                        }
                    }
                }
            }
        }

        // Await the coroutines to ensure they finish
        withContext(Dispatchers.IO) {
            rc.join()
            hbc.join()
        }

        // Wait until the test is interrupted
        latch.await()
        mainScope.cancel()
    }
}